package com.gitee.fanx.retty.spring;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.gitee.fanx.retty.NettyHttpOption;
import com.gitee.fanx.retty.NettyHttpServer;
import com.gitee.fanx.retty.spring.config.RettyProperties;
import com.gitee.fanx.retty.spring.springmvc.SpringMvcRouteMappingRegister;
import com.gitee.fanx.retty.web.ResponseHandler;
import com.gitee.fanx.retty.web.RouteMapping;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @author fanhang
 */
public class RettyServerBean implements ApplicationContextAware, InitializingBean {

	private ApplicationContext ctx;
	private ObjectMapper objectMapper;

	private RouteMapping routeMapping = new RouteMapping();
	private SpringMvcRouteMappingRegister routeMappingRegister;
	private RettyProperties rettyProperties;
	private NettyHttpOption nettyHttpOption;
	private com.gitee.fanx.retty.web.ExceptionHandler exceptionHandler;

	public RettyServerBean(RettyProperties rettyProperties) {
		this.rettyProperties = rettyProperties;
		this.objectMapper = new ObjectMapper();
		this.routeMappingRegister = new SpringMvcRouteMappingRegister(rettyProperties.getContextPath(), routeMapping,
				objectMapper);
		this.nettyHttpOption = new NettyHttpOption();
	}

	@Override
	public void setApplicationContext(ApplicationContext ctx) throws BeansException {
		this.ctx = ctx;

	}

	@Override
	public void afterPropertiesSet() throws Exception {
		Map<String, ResponseHandler> responseBodyMap = ctx.getBeansOfType(ResponseHandler.class);
		ResponseHandler responseHandler = null;
		if (!CollectionUtils.isEmpty(responseBodyMap)) {
			Assert.state(responseBodyMap.size() == 1, "multi ResponseHandler");
			responseHandler = responseBodyMap.values().stream().findFirst().get();
		}
		Map<String, Object> beanMap = ctx.getBeansWithAnnotation(RestControllerAdvice.class);
		if (!CollectionUtils.isEmpty(beanMap)) {
			this.exceptionHandler = new AnnotationExceptionHandler(beanMap.values());
		}
		Map<String, Object> beans = ctx.getBeansWithAnnotation(RestController.class);
		for (Object bean : beans.values()) {
			this.routeMappingRegister.registe(bean);
		}
		NettyHttpServer server = new NettyHttpServer(rettyProperties.getPort(), nettyHttpOption, routeMapping);
		if (responseHandler != null) {
			server.withResponseHandler(responseHandler);
		}
		if (this.exceptionHandler != null) {
			server.withRouteExceptionHandler(exceptionHandler);
		}
		try {
			server.start();
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
